package sto.orz.json.webapp.action;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import sto.orz.dao.HibernateGenericDao;
import sto.orz.json.JSONAdapter;
import sto.orz.json.JSONResponse;
import sto.orz.rptp.webapp.action.JSONProvideAction;
import sto.orz.webapp.action.BaseAction;

/*******************************************************************************
 * 一个JSON-RPC的简单实现。
 * 
 * request >>>
 * 
 * [GET] 可能为安全控制(url安全策略)原因选用。
 * 
 * [POST] LOTEX_JSON_ARGS = [
 *            "name" : "datasource",
 *            "value" : {
 *                "id":"12"
 *            },
 *            ["name","year"]
 *        ]
 * LOTEX_JSON_ARGS 为一个JSONArray，用为被调用的Java方法的参数数组。
 * 
 * response <<<
 * [JSON] 
 *     
 * XXX 是否需要统一 LOTEX_JSON_ARGS 格式?
 ******************************************************************************/
abstract public class BaseJSONAction extends BaseAction implements
		JSONProvideAction {
	private static final long				serialVersionUID	= -8919184364467109034L;
	public static final String				JSON_FUNCTION		= "todo";
	public static final String				JSON_RESPONSE		= "jsonResponse";

	// TODO 重构
	protected static Map<String, String>	models				= new HashMap<String, String>();
	static {
		models.put("Definition", "sto.orz.rptp.model.Definition");
		models.put("Attribute", "sto.orz.rptp.model.Attribute");
		models.put("Datasource", "sto.orz.rptp.model.Datasource");
		models.put("Dataset", "sto.orz.rptp.model.Dataset");
	}

	public static String getClassName(String modelAlias) {
		return models.get(modelAlias);
	}

	protected HibernateGenericDao	dao;
	protected JSONAdapter			json;
	protected String				LOTEX_JSON_ARGS;

	protected Method getJsonFunction() {
		for (Method jf : getClass().getMethods()) {
			if (jf.getName().equals(JSON_FUNCTION))
				return jf;
		}
		return null;
	}

	/*
	 * 现在支持 String.class,HashMap.class,Object[].class 拟将其用简洁的常量调用.比如 MAP =
	 * HashMap.class,ARRAY = OBJECT[].class
	 */
	protected <T> T getArg(Class<T> argType, Object arg) {
		if (argType == String.class)
			return (T) arg;
		if (argType == java.util.HashMap.class)
			return (T) getMap((JSONObject) arg);
		if (argType == Object[].class)
			return (T) ((JSONArray) arg).toArray();
		return null;
	}

	protected <T> T findUniqueBy(Class<T> entityClass, Object obj) {
		return (T) obj;
	}

	public JSONAdapter getJson() {
		return json;
	}

	protected Map<String, String> getMap(JSONObject arg) {
		Map<String, String> map = new HashMap<String, String>();
		Iterator<String> it = arg.keys();
		while (it.hasNext()) {
			String property = it.next();
			map.put(property, arg.getString(property));
		}
		return map;
	}

	protected Class loadModel(String name) throws ClassNotFoundException {
		return Class.forName(BaseJSONAction.getClassName(name));
	}

	protected String message(String msg) {
		json = new JSONResponse(false,msg);
		return JSON_RESPONSE;
	}

	public void setGenericDao(HibernateGenericDao dao) {
		this.dao = dao;
	}

	public void setLOTEX_JSON_ARGS(String lotex_json_args) {
		LOTEX_JSON_ARGS = lotex_json_args;
	}

	// XXX detailed exception?
	protected Object[] validArgs(Class... argTypes) throws Exception {
		JSONArray args = JSONArray.fromString(LOTEX_JSON_ARGS);
		Object[] ret = new Object[argTypes.length];
		for (int i = 0; i < argTypes.length; i++) {
			ret[i] = getArg(argTypes[i], args.get(i));
		}

		return ret;
	}

	public String execute() {
		if (StringUtils.isBlank(LOTEX_JSON_ARGS))
			return message("Please post LOTEX_JSON_ARGS!");
		Method jf = getJsonFunction();
		Class[] types = jf.getParameterTypes();
		Object[] args;
		try {
			args = validArgs(types);
		} catch (Exception e) {
			return message("LOTEX_JSON_ARGS not valid format!");
		}

		java.lang.reflect.Method method;
		try {
			method = this.getClass().getMethod(JSON_FUNCTION, types);
		} catch (SecurityException e) {
			return message(e.getLocalizedMessage());
		} catch (NoSuchMethodException e) {
			return message(e.getLocalizedMessage());
		}

		Object result;
		try {
			result = method.invoke(this, args);
		} catch (IllegalArgumentException e) {
			return message(e.getLocalizedMessage());
		} catch (IllegalAccessException e) {
			return message(e.getLocalizedMessage());
		} catch (InvocationTargetException e) {
			return message(e.getLocalizedMessage());
		}
		return (String) result;
	}
}
